// ==UserScript==
// @name         某云堂绕过防挂机机制脚本
// @namespace    https://terrason.oschina.io/experience/
// @version      2.0.3
// @description  跳过某云堂防挂机机制
// @author       Angus
// @supportURL   https://terrason.gitee.io/experience/2020/%E6%9F%90%E5%A0%82%E7%BB%95%E8%BF%87%E9%98%B2%E6%8C%82%E6%9C%BA%E6%9C%BA%E5%88%B6/
// @updateURL    https://terrason.gitee.io/experience/assets/js/skip-htykt-on-hook-defensive.user.js
// @downloadURL  https://terrason.gitee.io/experience/assets/js/skip-htykt-on-hook-defensive.user.js
// @match        https://train.casicloud.com/*
// @match        https://ecbead.com/*
// @grant        none
// ==/UserScript==

(function () {
    'use strict';
    if (location.host === 'train.casicloud.com' && !location.hash.startsWith('#/study/course/detail/')) return;
    if (location.host === 'ecbead.com' && !location.hash.startsWith('#/study/course/out-resource/')) return;

    waitForElements(['.player-wrapper'])
        .then((eles) => {
            const playerWrapper = eles[0];
            if (!playerWrapper) return Promise.reject(); //跳过不能识别的网页
            // iframe 交由 @match https://ecbead.com 处理
            if (playerWrapper.querySelector('iframe')) return Promise.reject();

            console.log('某云堂绕过防挂机机制脚本注入');

            return waitForElements(['.player-wrapper video', '.player-wrapper .course-side-catalog']);
        })
        .then((elements) => {
            const player = requireElement(elements[0], '绕过防挂机失败，找不到播放器！');
            //阻止防挂机机制
            function continueIfBlocked() {
                const alertShadow = document.querySelector('.page-alert .alert-shadow');
                if (!alertShadow) return;
                const cssDisplay = window.getComputedStyle(alertShadow).getPropertyValue('display');
                if (cssDisplay !== 'none') {
                    console.log('发现播放器被暂停，模拟点击"确定"按钮');
                    alertShadow.querySelector('.btn.btn-ok').click();
                }
            }
            player.addEventListener('pause', continueIfBlocked);

            //播放完自动跳转下一个
            const catalog = requireElement(elements[1], '无法自动切换下一节，找不到章节目录！');
            console.log('开启自动切换下一节...');
            window.setInterval(function () {
                continueIfBlocked();

                const playing = catalog.querySelector('.chapter-list-box.focus');
                const status = playing.querySelector('.section-item .item.pointer');
                const finished = status && status.innerText.trim() === '重新学习';
                const nextChapter = playing.nextElementSibling;
                console.debug('当前播放章节状态', playing, status, nextChapter);
                if (finished && nextChapter) {
                    console.log('模拟点击章节：', new ChapterTitle(nextChapter));
                    nextChapter.click();
                }
            }, 8000);
        })
        .catch(logAndAlert);

    function waitForElements(selectors, context) {
        context = context || document;
        return new Promise((resolve, reject) => {
            let retry = 0;
            const timer = window.setInterval(() => {
                const elements = selectors.map((s) => context.querySelector(s));
                if (elements.every(exists)) {
                    window.clearInterval(timer);
                    resolve(elements);
                    return;
                }
                retry += 1;
                if (retry === 60) {
                    window.clearInterval(timer);
                    resolve(elements);
                }
            }, 500);
        });
    }

    function exists(elem) {
        return !!elem;
    }
    function requireElement(element, errorMessage, subSelector) {
        if (!element) {
            throw new Error(errorMessage);
        }
        if (subSelector) {
            element = element.querySelector(subSelector);
            if (!element) {
                throw new Error(errorMessage);
            }
        }
        return element;
    }
    function logAndAlert(err) {
        if (err) {
            console.error(err);
            window.alert(err.message);
        }
    }

    function ChapterTitle(chapter) {
        this.chapter = chapter;
    }
    ChapterTitle.prototype.toString = function () {
        return this.chapter.querySelector('.chapter-item > .text-overflow').innerText;
    };
})();
